import type { PromiseFn } from '@/apis/schema/all'
import type { TableInstance } from '@arco-design/web-vue'
import type { Data } from '@arco-design/web-vue/es/_utils/types'
import type { Ref } from 'vue'
import { type MaybeRefOrGetter, ref, toValue } from 'vue'
export interface Pagination {
  total: number
  current: number
  pageSize: number
}

/**
 * 页码减一
 * @param pagination 分页数据
 * @param data data数据源
 * @param selected 选中数据(多选时使用)
 */
function decPageByData(
  pagination: Pagination,
  data: MaybeRefOrGetter<any[]>,
  selected?: MaybeRefOrGetter<any[]>
) {
  const isLastPage =
    pagination.current * pagination.pageSize >= pagination.total
  if (!isLastPage) return
  data = toValue(data)
  const current = pagination.current
  const dataLength = data.length
  const selectedLength = selected ? toValue(selected).length ?? 1 : 1
  const condition = current > 1 && selectedLength === dataLength
  if (condition) pagination.current--
}

// 定义参数类型
type OrderParams = {
  sort?: string | null
  order?: string | null
} & Record<string, any>

/**
 * - `tableRef` Ref<TableInstance>，用于获取 TableInstance 实例
 * - `checkedAll` Ref<boolean>，标记是否全选
 * - `selectedKeys` Ref<(string | number)[]>，存储选中的行的键值
 * - `indeterminate` Ref<boolean>，标记是否处于部分选中状态
 * - `onSelectChange` 用于处理行选中状态变化的函数
 * - `createSortChange` 用于处理排序变化的函数
 */
export type UseTableReturn = {
  tableRef: Ref<TableInstance | undefined>
  checkedAll: Ref<boolean>
  selectionRows: Ref<Data[]>
  selectedKeys: Ref<(string | number)[]>
  indeterminate: Ref<boolean>
  decPageByData: typeof decPageByData
  onSelectChange: (rowKeys: (string | number)[]) => void
  createSortChange: <T extends OrderParams>(
    data: T | Ref<T>
  ) => (dataIndex: string, direction: string) => void
}

interface HookOptions {
  clearSelectedKeys?: boolean
}

const defaultOptions: HookOptions = {
  clearSelectedKeys: true
}

// useTable 函数接收一个 PromiseFn 和一个数据源 Ref<Data[]> 作为参数
export const useTable = (
  fn: PromiseFn,
  dataSource: Ref<Data[]>,
  options?: HookOptions
): UseTableReturn => {
  options = { ...defaultOptions, ...options }
  // 创建一个 Ref 用于存储 TableInstance
  const tableRef = ref<TableInstance>()
  // 创建一个 Ref 用于存储选中的行的键值
  const selectedKeys = ref<(string | number)[]>([])
  // 创建一个 Ref 用于标记是否全选
  const checkedAll = ref(false)
  const selectionRows = ref<Data[]>([])

  // 使用 computed 计算数据源中未禁用的数据长度
  const dataLength = computed(
    () => dataSource.value.filter((item: Data) => !item?.disabled).length
  )

  // 使用 computed 计算是否处于部分选中状态
  const indeterminate = computed(() => {
    return (
      !!dataLength &&
      !!selectedKeys.value.length &&
      selectedKeys.value.length < dataLength.value
    )
  })

  // 创建处理排序变化的函数
  const createSortChange = <T extends OrderParams>(data: T | Ref<T>) => {
    return (dataIndex: string, direction: string) => {
      const params = isRef(data) ? data.value : data
      params.sort = direction && dataIndex
      params.order = direction && direction.replace('end', '')
      // 调用传入的 PromiseFn 处理数据
      fn()
    }
  }

  // 处理行选中状态变化的函数
  const onSelectChange = (rowKeys: (string | number)[]) => {
    // 更新全选状态和选中的行的键值
    checkedAll.value = rowKeys.length === dataSource.value.length

    selectedKeys.value = rowKeys
  }

  // 切换全选状态的函数
  const toggleAll = (val: boolean) => {
    // 调用 TableInstance 的 selectAll 方法
    tableRef.value?.selectAll?.(val)
  }

  // 监听全选状态的变化
  watch(checkedAll, async (val) => {
    // 根据全选状态执行相应操作
    if (val) toggleAll(true)
    else if (!val && !indeterminate.value) {
      await nextTick()
      toggleAll(false)
    }
  })

  // 监听传入数据 如果变化取消所有选择项
  watch(
    dataSource,
    async () => {
      if (!options?.clearSelectedKeys) {
        return
      }
      await nextTick()
      toggleAll(false)
      selectedKeys.value = []
    },
    { deep: true }
  )

  watch(
    () => selectedKeys.value,
    (v) => {
      selectionRows.value = dataSource.value.filter((item) =>
        v.includes(item[String(tableRef.value?.rowKey)])
      )
    },
    { deep: true }
  )
  // 返回需要在组件中使用的属性和方法
  return {
    tableRef,
    checkedAll,
    selectedKeys,
    selectionRows,
    indeterminate,
    onSelectChange,
    createSortChange,
    decPageByData
  }
}
